import 'package:dio/dio.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:oktoast/oktoast.dart';
import 'package:provider/provider.dart';
import 'ability/navigator_ability.dart';
import 'base_model.dart';
import 'net/NetHelp.dart';
import 'widget/Loading.dart' as loading;
import 'widget/Toast.dart';

enum PageState {
  loading,
  complete,
  fail,
  retry,
}

BuildContext navigatorContext;

mixin PageStateMixin on ChangeNotifier {
  PageState state = PageState.loading;

  checkInitDataCompleteState(BaseResponseModel model) {
    if (model.succeed) {
      complete();
      return true;
    }
    if (model.code == "10086")
      retry();
    else
      fail();
    return false;
  }

  loading() {
    state = PageState.loading;
    notifyListeners();
  }

  complete() {
    state = PageState.complete;
    notifyListeners();
  }

  fail() {
    state = PageState.fail;
    notifyListeners();
  }

  retry() {
    state = PageState.retry;
    notifyListeners();
  }
}

mixin HttpActionMixin {
  CancelToken cancelToken = CancelToken();

  Future<BaseResponseModel> post(
    String path, {
    String baseUrl: "",
    data,
    Map<String, dynamic> queryParameters,
    RequestOptions options,
    CancelToken cancelToken,
    ProgressCallback onSendProgress,
    ProgressCallback onReceiveProgress,
  }) async {
    Response respons = await NetHelp.dio.post(path,
        data: data,
        queryParameters: queryParameters,
        options: options != null
            ? options.merge(baseUrl: baseUrl)
            : baseUrl == null || baseUrl.isEmpty
                ? null
                : RequestOptions(baseUrl: baseUrl),
        cancelToken: cancelToken ?? this.cancelToken,
        onSendProgress: onSendProgress,
        onReceiveProgress: onReceiveProgress);
    return BaseResponseModel.map(respons.data);
  }

  Future<BaseResponseModel> get(
    String path, {
    String baseUrl: "",
    data,
    RequestOptions options,
    CancelToken cancelToken,
    ProgressCallback onReceiveProgress,
  }) async {
    Response respons = await NetHelp.dio.get(path,
        queryParameters: data,
        options: options != null
            ? options.merge(baseUrl: baseUrl)
            : baseUrl == null || baseUrl.isEmpty
                ? null
                : RequestOptions(baseUrl: baseUrl),
        cancelToken: cancelToken ?? this.cancelToken,
        onReceiveProgress: onReceiveProgress);
    return BaseResponseModel.map(respons.data);
  }
}

abstract class CunwControllNotify extends ChangeNotifier
    with
        HttpActionMixin,
        LoadingDialogMixin,
        PageStateMixin,
        NavigatorActionMixin2 {
  @override
  void dispose() {
    cancelToken.cancel("请求被取消");
    super.dispose();
  }
}

mixin LoadingDialogMixin {
  showLoadingDialog() {
    if (navigatorContext != null) loading.showLoadingDialog(navigatorContext);
  }

  hideLoadingDialog() async {
    if (navigatorContext != null)
      return await loading.dismissLoadingDialog(navigatorContext);
  }

  showToast(String message) {
    showToastWidget(
        ToastWidget(
          msg: message,
        ),
        dismissOtherToast: true);
  }

  dismissAllToasts() {
    dismissAllToast();
  }

  Future<T> autoFutureDialog<T>(Future<T> future) async {
    showLoadingDialog();
    T result;
    try {
      result = await future;
    } catch (e, s) {
      print(s);
    } finally{
      await hideLoadingDialog();
    }
    return result;
  }

  Future<List<T>> autoFutureListDialog<T>(List<Future<T>> futures) async {
    showLoadingDialog();
    var result = await Future.wait(futures);
    await hideLoadingDialog();
    return result;
  }

  Future<List<T>> autoFutureSortDialog<T>(List<Future<T>> futures) async {
    showLoadingDialog();
    var result = Future.forEach(futures, (element) async => await element);
    await hideLoadingDialog();
    return result;
  }
}

ChangeNotifierProvider<T> cnprovider<T extends CunwControllNotify>(
    Create<T> create,{bool lazy}) {
  return ChangeNotifierProvider<T>(
    create: create,
    lazy: lazy,
  );
}
